home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / tw14w12s.zoo / tw14w12s / winops.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-08  |  19.1 KB  |  958 lines

  1. /*
  2.  * Copyright 1992 Eric R. Smith. All rights reserved.
  3.  * Redistribution is permitted only if the distribution
  4.  * is not for profit, and only if all documentation
  5.  * (including, in particular, the file "copying")
  6.  * is included in the distribution in unmodified form.
  7.  * THIS PROGRAM COMES WITH ABSOLUTELY NO WARRANTY, NOT
  8.  * EVEN THE IMPLIED WARRANTIES OF MERCHANTIBILITY OR
  9.  * FITNESS FOR A PARTICULAR PURPOSE. USE AT YOUR OWN
  10.  * RISK.
  11.  */
  12. #include "xgem.h"
  13. #include <osbind.h>
  14. #include <mintbind.h>
  15. #include <fcntl.h>
  16. #include <signal.h>
  17. #include <string.h>
  18. #include <unistd.h>
  19. #include <stdlib.h>
  20. #include <errno.h>
  21. #include <time.h>
  22. #include "toswin_w.h"
  23. #include "twdefs.h"
  24. #include "twproto.h"
  25.  
  26. #define FLASHTIME 30
  27.  
  28. /* external flag: set to indicate the flag for opening a
  29.  * "global" file (if we need to) when we're starting up
  30.  */
  31. extern int global_flag;
  32.  
  33. /* file descriptors that have kids attached to them */
  34. long fd_mask = 0L;
  35.  
  36. /* file descriptor of TOSRUN */
  37. extern int trun_fd;
  38.  
  39. static void write_win __PROTO((TEXTWIN *, char *, int));
  40.  
  41. /*
  42.  * get a file name using the file selector.
  43.  * "title" is the file selector box title
  44.  * "path" is where to look for the file;
  45.  * "default_name" is a default name for the file;
  46.  * the final name selected is returned in "name"
  47.  */
  48.  
  49. int
  50. getfilename(title, name, path, default_name)
  51.     char *title;
  52.     char *name;
  53.     char *path, *default_name;
  54. {
  55.     extern char *rindex();
  56.     char *s;
  57.     int fresult, fbutton;
  58.     extern int gl_ap_version;
  59.  
  60.     if (path[0] == 0) {
  61.         path[0] = Dgetdrv() + 'A';
  62.         path[1] = ':';
  63.         (void)Dgetpath(&path[2], 0);
  64.         strcat(path, "\\");
  65.     }
  66.     for (s = path; *s; s++) {
  67.         if (*s == '*') goto nowildcard;
  68.     }
  69.     strcpy(s, "*.*");
  70.  
  71. nowildcard:
  72.     if (gl_ap_version >= 0x140)
  73.         fresult = fsel_exinput(path, default_name, &fbutton, title);
  74.     else
  75.         fresult = fsel_input(path, default_name, &fbutton);
  76.     if (fresult <= 0 || fbutton != 1 || !default_name[0])
  77.         return FAIL;
  78.     s = rindex(path, '\\');
  79.     if (!s)
  80.         s = &path[2];
  81.     else
  82.         s++;
  83.     *s = 0;
  84.     strcpy(name, path);
  85.     strcat(name, default_name);
  86.     return OK;
  87. }
  88.  
  89. /*
  90.  * if the program named by "fname" is a .TTP one, prompt the
  91.  * user for arguments and copy them into "argstr"; otherwise
  92.  * copy in a null command line. Return FAIL if the user
  93.  * cancelled the request.
  94.  */
  95.  
  96. int
  97. getargs(fname, argstr)
  98.     char *fname, *argstr;
  99. {
  100.     char *lastdot = 0;
  101.     int i, x, y, w, h;
  102.     TEDINFO *ted;
  103.     OBJECT *argdial;
  104.     char *inp;
  105.  
  106.     *argstr = 0;
  107.     while (*fname) {
  108.         if (*fname == '.')
  109.             lastdot = fname;
  110.         else if (*fname == '\\')
  111.             lastdot = 0;
  112.         fname++;
  113.     }
  114.     if (lastdot && !strcmp(lastdot, ".TTP")) {
  115.         rsrc_gaddr(0, ARGDIAL, &argdial);
  116.         ted = (TEDINFO *)argdial[ARGSTR].ob_spec;
  117.         inp = (char *)ted->te_ptext;
  118.         *inp = 0;
  119.         form_center(argdial, &x, &y, &w, &h);
  120.         wind_update(1);
  121.         form_dial(FMD_START, 0, 0, 32, 32, x, y, w, h);
  122.         if (win_flourishes)
  123.             form_dial(FMD_GROW, 0, 0, 32, 32, x, y, w, h);
  124.  
  125.         objc_draw(argdial, 0, 2, x, y, w, h);
  126.  
  127.         i = form_do(argdial, ARGSTR);
  128.  
  129.         if (win_flourishes)
  130.             form_dial(FMD_SHRINK, 0, 0, 32, 32, x, y, w, h);
  131.  
  132.         form_dial(FMD_FINISH, 0, 0, 32, 32, x, y, w, h);
  133.         objc_change(argdial, i, 0, x, y, w, h, NORMAL, 0);
  134.         wind_update(0);
  135.         if (i == ARGCAN) return FAIL;
  136.         strcpy(argstr, inp);
  137.     }
  138.     return OK;
  139. }
  140.  
  141. char progpath[128];
  142. char dfltprog[128];
  143.  
  144. int
  145. getprogname(name)
  146.     char *name;
  147. {
  148.     return getfilename(Strng(EXECPRG), name, progpath, dfltprog);
  149. }
  150.  
  151. /*
  152.  * typeit: type the user's input into a window. Note that this routine is
  153.  * called when doing a 'paste' operation, so we must watch out for possible
  154.  * deadlock conditions
  155.  */
  156.  
  157. #define READBUFSIZ 256
  158. static char buf[READBUFSIZ];
  159.  
  160. int
  161. typeit(w, code, shift)
  162.     WINDOW *w;
  163.     int code, shift;
  164. {
  165.     TEXTWIN *t = w->extra;
  166.     long offset, height;
  167.     long c = (code & 0x00ff) | (((long)code & 0x0000ff00) << 8L) |
  168.          ((long)shift << 24L);
  169.     long r;
  170.     if (t->miny) {
  171.         offset = t->miny * t->cheight;
  172.         if (offset > t->offy) {
  173.     /* we were looking at scroll back */
  174.     /* now move so the cursor is visible */
  175.             height = t->cheight * t->maxy - w->wi_h;
  176.             if (height <= 0)
  177.                 offset = 0;
  178.             else {
  179.                 offset = 1000L * t->cy * t->cheight/height;
  180.                 if (offset > 1000L) offset = 1000L;
  181.             }
  182.             (*w->vslid)(w, offset);
  183.         }
  184.     }
  185.  
  186.     if (t->fd) {
  187.         r = Foutstat(t->fd);
  188.         if (r <= 0) {
  189.             r = Fread(t->fd, (long)READBUFSIZ, buf);
  190.             if (r > 0) {
  191.                 write_win(t, buf, (int)r);
  192.             }
  193.             (void)Fselect(500,0L,0L,0L);
  194.             r = Foutstat(t->fd);
  195.         }
  196.         if (r > 0) {
  197.             (void)Fputchar(t->fd, c, 0);
  198.             return 1;
  199.         }
  200.     }
  201.     return 0;
  202. }
  203.  
  204. void (*oldtopped)(), (*oldclosed)();
  205.  
  206. extern MENU *sysbar;
  207. extern int appl_menus, sys_menu;
  208.  
  209. void
  210. top_menu(v, f)
  211.     WINDOW *v;
  212.     void (*f)();
  213. {
  214.     ENTRY *e;
  215.     TEXTWIN *t = v->extra;
  216.     TEXTWIN *oldt;
  217.     int enable = (v->wtype == TEXT_WIN);
  218.  
  219.     if (gl_topwin && gl_topwin->wtype == TEXT_WIN &&
  220.         gl_topwin->extra != t)
  221.         oldt = gl_topwin->extra;
  222.     else
  223.         oldt = 0;
  224.  
  225.     for (e = windowmenu->contents; e; e = e->next) {
  226.         if (e->entry[0] != '-')
  227.             if (enable)
  228.                 enable_entry(windowmenu, e);
  229.             else
  230.                 disable_entry(windowmenu, e);
  231.     }
  232.     for (e = gadgmenu->contents; e; e = e->next) {
  233.         if (e->entry[0] != '-')
  234.             if (enable)
  235.                 enable_entry(gadgmenu, e);
  236.             else
  237.                 disable_entry(gadgmenu, e);
  238.     }
  239.  
  240.     enable_entry(filemenu, closeentry);
  241.  
  242. #ifdef GLOBL_APPL_MENUS
  243.     if (v->menu && appl_menus) {
  244.         show_menu(v->menu);
  245.         sys_menu = 0;
  246.     } else if (!sys_menu) {
  247.         show_menu(sysbar);
  248.         sys_menu = 1;
  249.     }
  250. #endif
  251.     if (enable)
  252.         curs_off(t);
  253.     if (oldt) {
  254.     /* change the cursor states, maybe */
  255.         curs_off(oldt);
  256.     }
  257.     (*f)(v);
  258.     focuswin = gl_topwin;
  259.     if (enable) {
  260.         curs_on(t);
  261.         refresh_textwin(t);
  262.     }
  263.     if (oldt) {
  264.         curs_on(oldt);
  265.         refresh_textwin(oldt);
  266.     }
  267. }
  268.  
  269. static void
  270. top_text(v)
  271.     WINDOW *v;
  272. {
  273.     top_menu(v, oldtopped);
  274. }
  275.  
  276. static void
  277. desk_menu(v)
  278.     WINDOW *v;
  279. {
  280.     ENTRY *e;
  281.  
  282.     (*oldclosed)(v);
  283.     if (v->menu)
  284.         unloadmenu(v->menu);
  285.     if (!gl_topwin) {
  286.         for (e = windowmenu->contents; e; e = e->next) {
  287.             if (e->entry[0] != '-')
  288.                 disable_entry(windowmenu, e);
  289.         }
  290.         for (e = gadgmenu->contents; e; e = e->next) {
  291.             if (e->entry[0] != '-')
  292.                 disable_entry(gadgmenu, e);
  293.         }
  294.         disable_entry(filemenu, closeentry);
  295. #ifdef GLOBAL_APPL_MENUS
  296.         if (!sys_menu) {
  297.             show_menu(sysbar);
  298.             sys_menu = 1;
  299.         }
  300. #endif
  301.     }
  302. }
  303.  
  304. /*
  305.  * set up a new text window with a process running in it
  306.  * "progname" is the program's name;
  307.  * "progargs" are the arguments for it;
  308.  * "progdir" is the directory to change to;
  309.  * "x" and "y" give where the window is to be opened
  310.  * "rows" and "cols" are the number of rows and columns for it,
  311.  * respectively;
  312.  * "scroll" are the number of lines of scrollback to be
  313.  * alloted for the window
  314.  *
  315.  * NOTE: the window is *not* actually opened here; it's the
  316.  * caller's responsibility to do that.
  317.  */
  318.  
  319. TEXTWIN *
  320. newproc(progname, progargs, progdir, x, y, cols, rows, scroll, kind,
  321.  font, points)
  322.     char *progname, *progargs, *progdir;
  323.     int x, y, cols, rows, kind, scroll, font, points;
  324. {
  325.     extern void vt52_putch();
  326.     extern long termfunc;    /* set in main.c */
  327.     TEXTWIN *t;
  328.     int i, ourfd, kidfd;
  329. #ifdef OLD_WAY
  330.     long oldblock;
  331. #else
  332.     long r;
  333. #endif
  334.     static char termname[64];
  335.     static char argbuf[128];
  336.     struct winsize tw;
  337.     char *p, *arg, c;
  338.     char *newenv = 0;
  339.     int oldfont, oldheight;
  340.  
  341.     /* copy over the args */
  342.     p = argbuf+1;
  343.     arg = progargs;
  344.     for (i = 0; i < 125; i++) {
  345.         c = *arg++;
  346.         if (!c || c == '\r' || c == '\n') break;
  347.         *p++ = c;
  348.     }
  349.     *p = 0;
  350.     argbuf[0] = i;
  351.  
  352.     oldfont = default_font;
  353.     oldheight = default_height;
  354.     default_font = font;
  355.     default_height = points;
  356.     t = create_textwin(progname, x, y, cols, rows, scroll, kind);
  357.     default_font = oldfont;
  358.     default_height = oldheight;
  359.  
  360.     if (!t) {
  361.         form_alert(1, AlertStrng(NOWINS));
  362.         return 0;
  363.     }
  364.     t->output = vt52_putch;
  365.     t->prog = strdup(progname);
  366.     t->cmdlin = strdup(progargs);
  367.     t->progdir = strdup(progdir);
  368.     t->win->menu = loadmenu(progname);
  369.     if (t->win->menu) {
  370.         t->win->infostr = strdup(menustr(t->win->menu));
  371.     } else {
  372.         change_window_gadgets(t->win, t->win->wi_kind & ~INFO);
  373.     }
  374.  
  375.     newenv = envstr(progname, progargs, progdir, cols, rows);
  376.  
  377.     if (newenv && (env_options & E_ARGV)) {
  378.         if (!*argbuf)
  379.             argbuf[1] = 0;
  380.         argbuf[0] = 127;    /* mark ARGV arg. passing */
  381.     }
  382.  
  383.     strcpy(termname, "U:\\pipe\\pty.A");
  384.     for (i = 0; i < 20; i++) {
  385.         termname[12] = 'A' + i;
  386.         ourfd = Fcreate(termname, FA_SYSTEM|FA_HIDDEN|global_flag);
  387.         if (ourfd > 0) {
  388.         /* set to non-delay mode, so Fread() won't block */
  389.             (void)Fcntl(ourfd, (long)O_NDELAY, F_SETFL);
  390.             break;
  391.         }
  392.     }
  393.     if (ourfd < 0) {
  394.         form_alert(1, AlertStrng(NOPTY));
  395. abort_open:
  396.         destroy_textwin(t);
  397.         return 0;
  398.     }
  399.     t->fd = ourfd;
  400.     tw.ws_xpixel = tw.ws_ypixel = 0;
  401.     tw.ws_row = rows;
  402.     tw.ws_col = cols;
  403.  
  404.     (void)Fcntl(ourfd, &tw, TIOCSWINSZ);
  405.     t->win->keyinp = typeit;
  406.     t->win->mouseinp = win_click;
  407.     oldtopped = t->win->topped;
  408.     t->win->topped = top_text;
  409.     oldclosed = t->win->closed;
  410.     t->win->closed = desk_menu;
  411.  
  412. #ifdef OLD_WAY
  413.     oldblock = Psigblock(1L << SIGCHLD);
  414. #endif
  415.  
  416.     i = Pvfork();
  417.     if (i < 0) {
  418.         (void)Fclose(ourfd);
  419. #ifdef OLD_WAY
  420.         (void)Psigsetmask(oldblock);
  421. #endif
  422.         form_alert(1, AlertStrng(NOPROC));
  423.         goto abort_open;
  424.     } else if (i == 0) {
  425.         if (oldACC)
  426.             (void)Setexc(0x102, termfunc);
  427. #ifndef OLD_WAY
  428.         i = Pvfork();
  429.         if (i != 0)
  430.             Pterm(i);
  431. #endif
  432.         (void)Psetpgrp(0, 0);
  433.         kidfd = Fopen(termname, 2);
  434.         if (kidfd < 0) _exit(998);
  435.         (void)Fforce(-1, kidfd);
  436.         (void)Fforce(0, kidfd);
  437.         (void)Fforce(1, kidfd);
  438.         (void)Fforce(2, kidfd);
  439.         (void)Fclose(kidfd);
  440.         (void)chdir(progdir);
  441.         i = Pexec(200, progname, argbuf, newenv);
  442.         _exit(i);
  443.     }
  444.  
  445. #ifndef OLD_WAY
  446. #define WNOHANG 1
  447. /* reap the exit code of the just terminated process */
  448.     do {
  449.         r = Pwait3(WNOHANG, (void *)0);
  450.     } while (((r & 0xffff0000L) >> 16L) != i);
  451.     i = r & 0x0000ffff;
  452. #endif
  453.     t->pgrp = i;
  454.     if (!global_flag)
  455.         fd_mask |= (1L << ourfd);
  456. /* turn on the cursor in the window */
  457.     (*t->output)(t, '\033');
  458.     (*t->output)(t, 'e');
  459.  
  460. /* and make it flash */
  461.     (*t->output)(t, '\033');
  462.     (*t->output)(t, 't');
  463.     (*t->output)(t, ' '+FLASHTIME);
  464.  
  465. /* align the window, if necessary */
  466.     if (align_windows)
  467.         t->win->wi_x &= ~7;
  468.  
  469. #ifdef OLD_WAY
  470.     (void)Psigsetmask(oldblock);
  471. #endif
  472.  
  473.     if (newenv) free(newenv);
  474.  
  475.     return t;
  476. }
  477.  
  478. /* After this many bytes have been written to a window, it's time to
  479.  * update it. Note that we must also keep a timer and update all windows
  480.  * when the timer expires, or else small writes will never be shown!
  481.  */
  482. #define THRESHOLD 400
  483.  
  484. static void
  485. write_win(t, b, cnt)
  486.     TEXTWIN *t;
  487.     char *b;
  488.     int cnt;
  489. {
  490.     unsigned char *buf = (unsigned char *)b, c;
  491.     int limit = smoothscroll ? 1 : NROWS(t) - 1;
  492.  
  493.     while (cnt-- > 0) {
  494.         c = *buf++;
  495.         (*t->output)(t, c);
  496.         t->nbytes++;
  497.         if (t->nbytes >= THRESHOLD || t->scrolled >= limit) {
  498.             refresh_textwin(t);
  499.         }
  500.     }
  501. }
  502.  
  503. #define EIHNDL -37
  504.  
  505. static char exit_msg[] = "\r\n<EXITED>\r\n";
  506.  
  507. static void
  508. rebuild_fdmask(which)
  509.     long which;
  510. {
  511.     int i;
  512.     WINDOW *w, *wnext;
  513.     TEXTWIN *t;
  514.  
  515.     for (i = 0; i < 32; i++) {
  516.         if ((which & (1L << i)) && (Finstat(i) < 0)) {
  517.         /* window has died now */
  518.             fd_mask &= ~(1L << i);
  519.             for (w = gl_winlist; w; w = wnext) {
  520.                 wnext = w->next;
  521.                 if (w->wtype != TEXT_WIN) continue;
  522.                 t = w->extra;
  523.                 if (t && t->fd == i) {
  524.                     if (autoclose)
  525.                         (*w->closed)(w);
  526.                     else {
  527.                         write_win(t, exit_msg,
  528.                             (int)strlen(exit_msg));
  529.                         refresh_textwin(t);
  530.                         (void)Fclose(i);
  531.                         t->fd = 0;
  532.                     }
  533.                 }
  534.             }
  535.         }
  536.     }
  537. }
  538.  
  539. void
  540. exec_tos(buf)
  541.     char *buf;
  542. {
  543.     TEXTWIN *t;
  544.     char *dir, *name, *args;
  545.  
  546.     dir = buf;
  547.     while (*buf && *buf != ' ') buf++;
  548.     if (*buf) *buf++ = 0;
  549.     name = buf;
  550.     while (*buf && *buf != ' ') buf++;
  551.     if (*buf) *buf++ = 0;
  552.     args = buf;
  553.     t = newproc(name, args, dir, 0, 0, stdcol, stdrow, stdscroll, default_kind,
  554.          default_font, default_height);
  555.     if (_app || opened)
  556.         open_window(t->win);
  557. }
  558.  
  559. #ifdef WWA_GEM_RUN
  560. void
  561. exec_tos_ext(buf,x,y,w,h,scroll,fontnumber,fontsize)
  562.     char *buf;
  563.     int x,y,w,h,scroll;
  564.     int fontnumber;
  565.     int fontsize;
  566. {
  567.     TEXTWIN *t;
  568.     char *dir, *name, *args;
  569.  
  570.     dir = buf;
  571.     while (*buf && *buf != ' ') buf++;
  572.     if (*buf) *buf++ = 0;
  573.     name = buf;
  574.     while (*buf && *buf != ' ') buf++;
  575.     if (*buf) *buf++ = 0;
  576.     args = buf;
  577.  
  578.  
  579.     t = newproc(name, args, dir, x, y, w, h, stdscroll, default_kind,
  580.          fontnumber, fontsize);
  581.     if (_app || opened)
  582.         open_window(t->win);
  583. }
  584.  
  585. void
  586. runprog(progname, progargs, progdir)
  587.     char *progname, *progargs, *progdir;
  588. {
  589.     int i;
  590.     int child;
  591.     long wait;
  592.     static char argbuf[128];
  593.     char *p, *arg, c;
  594.     char *newenv = 0;
  595.  
  596.     /* copy over the args */
  597.     p = argbuf+1;
  598.     arg = progargs;
  599.     for (i = 0; i < 125; i++) {
  600.         c = *arg++;
  601.         if (!c || c == '\r' || c == '\n') break;
  602.         *p++ = c;
  603.     }
  604.     *p = 0;
  605.     argbuf[0] = i;
  606.  
  607.     newenv = envstr(progname, progargs, progdir, stdcol, stdrow);
  608.  
  609.     if (newenv && (env_options & E_ARGV)) {
  610.         if (!*argbuf)
  611.             argbuf[1] = 0;
  612.         argbuf[0] = 127;    /* mark ARGV arg. passing */
  613.     }
  614.  
  615.     child=Pexec(100, progname, argbuf, newenv);
  616.     do {
  617.         wait=Pwait3(0,0);
  618.     } while (wait!=ENOENT && wait>>16 != child);
  619.  
  620.     if (newenv) free(newenv);
  621. }
  622.  
  623. void
  624. exec_gem(buf)
  625.     char *buf;
  626. {
  627.     char *dir, *name, *args;
  628.     char olddir[256];
  629.     extern int opened;
  630.  
  631.     dir = buf;
  632.     while (*buf && *buf != ' ') buf++;
  633.     if (*buf) *buf++ = 0;
  634.     name = buf;
  635.     while (*buf && *buf != ' ') buf++;
  636.     if (*buf) *buf++ = 0;
  637.     args = buf;
  638.  
  639.     olddir[0]=Dgetdrv() + 'A';
  640.     olddir[1]=':';
  641.     Dgetpath(olddir+2,0);
  642.     if (!olddir[2]) {
  643.         olddir[2]='\\';
  644.         olddir[3]=0;
  645.     }
  646.  
  647.     /* Hack to shutdown&restart by using acc code! */
  648.     opened=1;
  649.  
  650.     desk_menu_show(0);
  651.     ac_close();
  652.  
  653.     (void)chdir(dir);
  654.  
  655.     runprog(name, args, dir);
  656.  
  657.     (void)chdir(olddir);
  658.  
  659.     ac_open();
  660.     desk_menu_show(1);
  661. }
  662.  
  663. int scanint(buf)
  664.     char** buf;
  665. {
  666.     int n=0;
  667.     while (**buf >= '0' && **buf <= '9') {
  668.         n=n*10+**buf-'0';
  669.         (*buf)++;
  670.     }
  671.     (*buf)++; /* skip space */
  672.  
  673.     return n;
  674. }
  675. #endif
  676.  
  677. static long lasthz;
  678.  
  679. void
  680. fd_input()
  681. {
  682. #define MAX_DELAY 3        /* max no. of 50Hz ticks before a refresh */
  683.     long readfds, r, checkdead;
  684.     int read;
  685.     int workdone = 0;
  686.     WINDOW *w;
  687.     TEXTWIN *t;
  688.     int updtime;
  689.     long newhz;
  690.  
  691.     r  = 0;
  692.     checkdead = 0;
  693.  
  694.     newhz = clock();
  695.     updtime = (newhz - lasthz) >> 2;
  696.     lasthz = newhz;
  697.  
  698.     if (fd_mask) {
  699.         readfds = fd_mask;
  700.         if ((r = Fselect(1, &readfds, 0L, 0L)) > 0) {
  701.             if (trun_fd && (readfds & (1L << trun_fd))) {
  702.                 read = Finstat(trun_fd);
  703.                 if (read > 0)
  704.                     read = Fread(trun_fd, (long)READBUFSIZ,
  705.                              buf);
  706.                 if (read > 0) {
  707. #ifdef WWA_EXT_TOSRUN
  708.                     char* prg_and_args=buf;
  709.                     int gem_not_tos=0;
  710.                     int x=0,y=0,w=0,h=0; /* Only valid if w!=0 */
  711.                     char* fontname=0;
  712.                     int fontnumber;
  713.                     int fontsize=0;
  714.                     int scroll=-1;
  715.  
  716.                     int special=1;
  717.                     while (special) {
  718.                         switch (prg_and_args[0]) {
  719.                          default:
  720.                             special=0;
  721.                         break; case '\01':
  722.                             prg_and_args++;
  723.                             gem_not_tos=1;
  724.                         break; case '\02':
  725.                             prg_and_args++;
  726.                             x=scanint(&prg_and_args);
  727.                             y=scanint(&prg_and_args);
  728.                             w=scanint(&prg_and_args);
  729.                             h=scanint(&prg_and_args);
  730.                         break; case '\03':
  731.                             prg_and_args++;
  732.                             fontname=prg_and_args;
  733.                             while (*prg_and_args != '@')
  734.                                 prg_and_args++;
  735.                             *prg_and_args='\0';
  736.                             prg_and_args++;
  737.                             fontsize=scanint(&prg_and_args);
  738.                         }
  739.                     }
  740.  
  741.                     if (!w) {
  742.                         x=0;
  743.                         y=0;
  744.                         w=stdcol;
  745.                         h=stdrow;
  746.                     }
  747.  
  748.                     if (!fontname) {
  749.                         fontnumber=default_font;
  750.                         fontsize=default_height;
  751.                     } else {
  752.                         fontnumber=find_font_named(fontname);
  753.                         if (fontnumber<0) { /* not found */
  754.                             fontname=0;
  755.                         }
  756.                     }
  757.  
  758.                     if (!fontname) {
  759.                         fontnumber=default_font;
  760.                         fontsize=default_height;
  761.                     }
  762.  
  763.                     if (scroll>=0) {
  764.                         scroll=stdscroll;
  765.                     }
  766.  
  767.                     if (gem_not_tos) {
  768.                         exec_gem(prg_and_args);
  769.                     } else {
  770.                         exec_tos_ext(prg_and_args,x,y,w,h,scroll,fontnumber,fontsize);
  771.                     }
  772. #else
  773.                     exec_tos(prg_and_args);
  774. #endif
  775.                 }
  776.             }
  777.             for (w = gl_winlist; w; w = w->next) {
  778.                 if (w->wtype != TEXT_WIN) continue;
  779.                 t = w->extra;
  780.                 if (!t || !t->fd) continue;
  781.                 if (readfds & (1L << t->fd)) {
  782.                     read = Fread(t->fd, (long)READBUFSIZ,
  783.                              buf);
  784.                     if (read > 0) {
  785.                         write_win(t, buf, read);
  786.                     } else {
  787.                         checkdead |= (1L << t->fd);
  788.                     }
  789.                 }
  790.             }
  791.             workdone = 1;
  792.         }
  793.         if (checkdead)
  794.             rebuild_fdmask(checkdead);
  795.     }
  796.     if (r == EIHNDL) {    /* invalid handle?? */
  797.         rebuild_fdmask(fd_mask);
  798.     }
  799.  
  800.     if (workdone) {
  801.         gl_timer = MultiTOS ? SHORTWAIT : NOMULTIWAIT;
  802.     } else {
  803.         gl_timer = MultiTOS ? LONGWAIT : NOMULTIWAIT;
  804.     }
  805.  
  806. /* for all windows on screen, see if it's time to refresh them */
  807.     for (w = gl_winlist; w; w = w->next) {
  808.         if (w->wtype != TEXT_WIN) continue;
  809.         t = w->extra;
  810.     /* should we flash the cursor in this window? */
  811.         if (t->flashperiod) {
  812.             t->flashtimer -= updtime;
  813.             if (t->flashtimer <= 0) {
  814.                 t->flashtimer = t->flashperiod;
  815.                 curs_flash(t);
  816.                 t->nbytes++;
  817.             }
  818.         }
  819.         if (!t || !t->fd || !t->nbytes) continue;
  820.         t->draw_time += updtime;
  821.         if (t->draw_time < MAX_DELAY) continue;
  822.         refresh_textwin(t);
  823.     }
  824. }
  825.  
  826. /*
  827.  * similar to fd_input, but used only when we're an ACC;
  828.  * this loop doesn't use Fselect, so it's less efficient
  829.  */
  830.  
  831. void
  832. acc_input()
  833. {
  834.     long r, checkdead;
  835.     int read;
  836.     int workdone = 0;
  837.     WINDOW *w;
  838.     TEXTWIN *t;
  839.     int updtime;
  840.     long newhz;
  841.  
  842.     r  = 0;
  843.     checkdead = 0;
  844.  
  845.     newhz = clock();
  846.     updtime = (newhz - lasthz) >> 2;
  847.     lasthz = newhz;
  848.  
  849.     read = Finstat(trun_fd);
  850.     if (read > 0) {
  851.         read = Fread(trun_fd, (long)READBUFSIZ, buf);
  852.         if (read > 0)
  853.             exec_tos(buf);
  854.     }
  855.     for (w = gl_winlist; w; w = w->next) {
  856.         if (w->wtype != TEXT_WIN) continue;
  857.         t = w->extra;
  858.         if (!t || !t->fd) continue;
  859.         if ((r = Finstat(t->fd)) != 0) {
  860.             read = Fread(t->fd, (long)READBUFSIZ, buf);
  861.             if (read > 0) {
  862.                 write_win(t, buf, read);
  863.             } else if (r < 0) {
  864.                 if (autoclose) {
  865.                     (*w->closed)(w);
  866.                 } else {
  867.                     write_win(t, exit_msg,
  868.                          (int)strlen(exit_msg));
  869.                     refresh_textwin(t);
  870.                     (void)Fclose(t->fd);
  871.                     t->fd = 0;
  872.                 }
  873.             }
  874.             workdone = 1;
  875.         }
  876.     }
  877.  
  878.     if (workdone) {
  879.         gl_timer = MultiTOS ? SHORTWAIT : NOMULTIWAIT;
  880.     } else {
  881.         gl_timer = MultiTOS ? LONGWAIT : NOMULTIWAIT;
  882.     }
  883.  
  884. /* for all windows on screen, see if it's time to refresh them */
  885.     for (w = gl_winlist; w; w = w->next) {
  886.         if (w->wtype != TEXT_WIN) continue;
  887.         if (w->wi_handle < 0) continue;
  888.         t = w->extra;
  889.     /* should we flash the cursor in this window? */
  890.         if (t->flashperiod) {
  891.             t->flashtimer -= updtime;
  892.             if (t->flashtimer <= 0) {
  893.                 t->flashtimer = t->flashperiod;
  894.                 curs_flash(t);
  895.                 t->nbytes++;
  896.             }
  897.         }
  898.         if (!t || !t->fd || !t->nbytes) continue;
  899.         t->draw_time += updtime;
  900.         if (t->draw_time < MAX_DELAY) continue;
  901.         refresh_textwin(t);
  902.     }
  903. }
  904.  
  905. /*
  906.  * send an untranslated character to the top window
  907.  */
  908.  
  909. void
  910. send_char()
  911. {
  912.     WINDOW *v;
  913.     OBJECT *quote_dial;
  914.     int event, mshift, keycode, dummy;
  915.     int x, y, w, h;
  916.  
  917.     v = gl_topwin;
  918.     if (v && v->wtype == TEXT_WIN) {
  919.         event = evnt_multi(MU_KEYBD|MU_TIMER,
  920.             0, 0, 0,
  921.             0, 0, 0, 0, 0,
  922.             0, 0, 0, 0, 0,
  923.             NULL,
  924.             1200L,        /* wait 1.2 seconds */
  925.             &dummy, &dummy, &dummy, &mshift,
  926.             &keycode, &dummy);
  927.         if (event & MU_KEYBD) {
  928.             (*v->keyinp)(v, keycode, mshift);
  929.         } else {
  930.             rsrc_gaddr(0, QUOTEIT, "e_dial);
  931.             form_center(quote_dial, &x, &y, &w, &h);
  932.             wind_update(BEG_MCTRL);
  933.             form_dial(FMD_START, 0, 0, 32, 32, x, y, w, h);
  934.             if (win_flourishes)
  935.                 form_dial(FMD_GROW, 0, 0, 32, 32, x, y, w, h);
  936.  
  937.             objc_draw(quote_dial, 0, 2, x, y, w, h);
  938.             event = evnt_multi(MU_KEYBD|MU_BUTTON,
  939.                 0x0101, 0x0003, 0,
  940.                 0, 0, 0, 0, 0,
  941.                 0, 0, 0, 0, 0,
  942.                 NULL,
  943.                 0L,
  944.                 &dummy, &dummy, &dummy, &mshift,
  945.                 &keycode, &dummy);
  946.  
  947.             if (win_flourishes)
  948.                 form_dial(FMD_SHRINK, 0, 0, 32, 32, x, y, w, h);
  949.             form_dial(FMD_FINISH, 0, 0, 32, 32, x, y, w, h);
  950.             wind_update(END_MCTRL);
  951.             if (event & MU_KEYBD) {
  952.                 (*v->keyinp)(v, keycode, mshift);
  953.             }
  954.         }
  955.     }
  956.  
  957. }
  958.